package org.free.utils.jfinal;

import org.free.utils.jfinal.annotation.Bind;
import org.free.utils.jfinal.annotation.ViewPath;
import org.free.utils.jfinal.annotation.PrimaryKey;
import org.free.utils.jfinal.annotation.Table;
import com.jfinal.config.Routes;
import com.jfinal.plugin.activerecord.ActiveRecordPlugin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Enumeration;

/**
 * Created by Zhangyi@qq:81938728 on 2015/12/12.
 */
@SuppressWarnings("ALL")
public class MappingHelper {

    private final static Logger LOGGER = LoggerFactory.getLogger(MappingHelper.class);

    public static class Controller {

        public static void addRoutes(Routes me, String controllerClasspath, final String controllerEndless) {
            addRoutes(me, controllerClasspath, "", controllerEndless);
        }

        public static void addRoutes(Routes me, String controllerClasspath, final String urlFilter, final String controllerEndless) {
            try {
                String packageName = controllerClasspath.replace(".", "/");
                Enumeration<URL> dirs = Thread.currentThread().getContextClassLoader().getResources(packageName);
                while (dirs.hasMoreElements()) {
                    URL url = dirs.nextElement();
                    if ("file".equals(url.getProtocol())) {
                        String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
                        addRoutes(me, "", new File(filePath), controllerClasspath, urlFilter, controllerEndless);
                    }
                }
            } catch (IOException e) {
                LOGGER.error("", e);
            }
        }

        private static void addRoutes(Routes me, String path, File dir, String controllerClasspath, final String urlFilter, final String controllerEndless) {
            File[] files = dir.listFiles(new FileFilter() {
                public boolean accept(File pathname) {
                    return pathname.isDirectory() || pathname.getName().endsWith(controllerEndless + ".class"); //Controller.class
                }
            });
            for (File file : files) {
                if (file.isDirectory()) {
                    addRoutes(me, path.length() == 0 ? file.getName() : (path + "." + file.getName()), file, controllerClasspath, urlFilter, controllerEndless);
                } else {
                    String className = file.getName().substring(0, file.getName().length() - 6);
                    try {
                        Class clazz = Thread.currentThread().getContextClassLoader().loadClass(controllerClasspath + "." + (path.length() == 0 ? "" : (path + ".")) + className);
                        String bindUrl = null;
                        String bindPath = null;
                        if (clazz.isAnnotationPresent(Bind.class)) {
                            Bind bind = (Bind) clazz.getAnnotation(Bind.class);
                            bindUrl = bind.value();
                        }
                        if (clazz.isAnnotationPresent(ViewPath.class)) {
                            ViewPath p = (ViewPath) clazz.getAnnotation(ViewPath.class);
                            bindPath = p.value();
                        }
                        if (bindUrl != null) {
                            bindUrl = urlFilter + bindUrl;
                            if (bindPath != null) me.add(bindUrl, clazz, bindPath);
                            else me.add(bindUrl, clazz);
                            LOGGER.info("AddRoute=======>uri:" + bindUrl + ", path:" + bindPath + ", class:" + clazz.getName());
                        } else {
                            //按目录结构绑定
                            String controllerName = className.substring(0, className.length() - controllerEndless.length());
                            char initial = controllerName.charAt(0);
                            if (initial >= 'A' && initial <= 'Z') {
                                controllerName = (char) (((int) initial) + 32) + controllerName.substring(1);
                            }
                            bindUrl = urlFilter + ((path.length() == 0 ? "" : "." + path) + "." + controllerName).replace(".", "/");
                            if (bindPath != null)
                                me.add(bindUrl, clazz, bindPath);
                            else me.add(bindUrl, clazz);
                            LOGGER.info("AddRoute=======>uri:" + bindUrl + ", path:" + bindPath + ", class:" + clazz.getName());
                        }
                    } catch (Exception e) {
                        LOGGER.error("", e);
                    }
                }
            }
        }

    }

    public static class Model {

        public static void mappingModels(ActiveRecordPlugin arp, String modelClasspath, String dbName) {
            try {
                String packageName = modelClasspath.replace(".", "/") + "/" + dbName;
                Enumeration<URL> dirs = Thread.currentThread().getContextClassLoader().getResources(packageName);
                while (dirs.hasMoreElements()) {
                    URL url = dirs.nextElement();
                    if ("file".equals(url.getProtocol())) {
                        String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
                        mappingModels(arp, modelClasspath + "." + dbName, new File(filePath));
                    }
                }
            } catch (IOException e) {
                LOGGER.error("", e);
            }
        }

        private static void mappingModels(ActiveRecordPlugin arp, String packageName, File dir) {
            File[] files = dir.listFiles(new FileFilter() {
                public boolean accept(File pathname) {
                    return pathname.getName().endsWith(".class");
                }
            });
            for (File file : files) {
                if (file.isDirectory()) {
                    mappingModels(arp, packageName + "." + file.getName(), file);
                } else {
                    String className = file.getName().substring(0, file.getName().length() - 6);
                    try {
                        Class clazz = Thread.currentThread().getContextClassLoader().loadClass(packageName + "." + className);
                        String tableName = null;
                        String priKey = null;
                        if (clazz.isAnnotationPresent(Table.class)) {
                            Table table = (Table) clazz.getAnnotation(Table.class);
                            tableName = table.value();
                        }
                        if (clazz.isAnnotationPresent(PrimaryKey.class)) {
                            PrimaryKey pkey = (PrimaryKey) clazz.getAnnotation(PrimaryKey.class);
                            priKey = pkey.value();
                        }
                        if (tableName != null) {
                            if (priKey != null) arp.addMapping(tableName, priKey, clazz);
                            else arp.addMapping(tableName, clazz);
                            LOGGER.info("MappingModel=======>table:" + tableName + ", priKey:" + priKey + ", class:" + clazz.getName());
                        }
                    } catch (Exception e) {
                        LOGGER.error("", e);
                    }
                }
            }
        }

    }

}
